using System;
using System.Collections.Generic;
using System.Linq;
using Urs.Core.Caching;
using Urs.Core.Data;
using Urs.Data.Domain.Directory;

namespace Urs.Services.Directory
{
    public partial class AreaService : IAreaService
    {
        #region Constants

        private const string AREAS_ALL_KEY = "Urs.Area.all-{0}";
        private const string AREAS_PATTERN_KEY = "Urs.Area.";

        #endregion

        #region Fields

        private readonly IRepository<Area> _areaRepository;
        private readonly ICacheManager _cacheManager;

        #endregion

        #region Ctor

        public AreaService(ICacheManager cacheManager,
            IRepository<Area> AreaRepository)
        {
            _cacheManager = cacheManager;
            _areaRepository = AreaRepository;
        }

        #endregion

        #region Methods

        public virtual void DeleteArea(Area Area)
        {
            if (Area == null)
                throw new ArgumentNullException("Area");

            _areaRepository.Delete(Area);

            _cacheManager.RemoveByPattern(AREAS_PATTERN_KEY);

        }

        public virtual IList<string> GetProvinces()
        {
            var query = from sp in _areaRepository.Table
                        orderby sp.DisplayOrder
                        select sp.ProvinceName;
            var provinces = query.Distinct().ToList();
            return provinces;
        }
        public virtual IList<string> GetCities(string provincename)
        {
            var query = from sp in _areaRepository.Table
                        orderby sp.DisplayOrder
                        where sp.ProvinceName == provincename
                        select sp.CityName;
            var cities = query.Distinct().ToList();
            return cities;
        }
        public virtual IList<string> GetAreas(string provincename, string cityname)
        {
            var query = from sp in _areaRepository.Table
                        orderby sp.DisplayOrder
                        where sp.ProvinceName == provincename && sp.CityName == cityname
                        select sp.AreaName;
            var areas = query.Distinct().ToList();
            return areas;
        }

        public IList<AreaCodeName> GetProvincesByCode()
        {
            var query = from sp in _areaRepository.Table
                        orderby sp.DisplayOrder
                        select new AreaCodeName { Code = sp.ProvinceCode, Name = sp.ProvinceName };
            var provinces = query.Distinct().ToList();
            return provinces;
        }

        public IList<AreaCodeName> GetCitiesByProvinceCode(string provinceCode)
        {
            var query = from sp in _areaRepository.Table
                        orderby sp.DisplayOrder
                        where sp.ProvinceCode == provinceCode
                        select new AreaCodeName { Code = sp.CityCode, Name = sp.CityName };
            var cities = query.Distinct().ToList();
            return cities;
        }

        public AreaCodeName GetProvinceByName(string provinceName)
        {
            var query = from sp in _areaRepository.Table
                        orderby sp.DisplayOrder
                        where sp.ProvinceName == provinceName
                        select new AreaCodeName { Code = sp.ProvinceCode, Name = sp.ProvinceName };
            var entity = query.FirstOrDefault();
            return entity;
        }

        public AreaCodeName GetCityByName(string provinceName, string cityName)
        {
            var query = from sp in _areaRepository.Table
                        orderby sp.DisplayOrder
                        where sp.ProvinceName == provinceName && sp.CityName == cityName
                        select new AreaCodeName { Code = sp.CityCode, Name = sp.CityName };
            var entity = query.FirstOrDefault();
            return entity;
        }

        public AreaCodeName GetAreaByName(string provinceName, string cityName, string areaName)
        {
            var query = from sp in _areaRepository.Table
                        orderby sp.DisplayOrder
                        where sp.ProvinceName == provinceName && sp.CityName == cityName && sp.AreaName == areaName
                        select new AreaCodeName { Code = sp.AreaCode, Name = sp.AreaName };
            var entity = query.FirstOrDefault();
            return entity;
        }


        public AreaCodeName GetProvinceByCode(string provinceCode)
        {
            var query = from sp in _areaRepository.Table
                        orderby sp.DisplayOrder
                        where sp.ProvinceCode == provinceCode
                        select new AreaCodeName { Code = sp.ProvinceCode, Name = sp.ProvinceName };
            var entity = query.FirstOrDefault();
            return entity;
        }
        public AreaCodeName GetCityByCode(string provinceCode, string cityCode)
        {
            var query = from sp in _areaRepository.Table
                        orderby sp.DisplayOrder
                        where sp.ProvinceCode == provinceCode && sp.CityCode == cityCode
                        select new AreaCodeName { Code = sp.CityCode, Name = sp.CityName };
            var entity = query.FirstOrDefault();
            return entity;
        }
        public AreaCodeName GetAreaByCode(string provinceCode, string cityCode, string areaCode)
        {
            var query = from sp in _areaRepository.Table
                        orderby sp.DisplayOrder
                        where sp.ProvinceCode == provinceCode && sp.CityCode == cityCode && sp.AreaCode == areaCode
                        select new AreaCodeName { Code = sp.AreaCode, Name = sp.AreaName };
            var entity = query.FirstOrDefault();
            return entity;
        }

        public Area GetCityByCityCode(string cityCode)
        {
            var query = from sp in _areaRepository.Table
                        orderby sp.DisplayOrder
                        where sp.CityCode == cityCode
                        select sp;
            var area = query.FirstOrDefault();
            return area;
        }
        public IList<AreaCodeName> GetAreasByCode(string provinceCode, string cityCode)
        {
            var query = from sp in _areaRepository.Table
                        orderby sp.DisplayOrder
                        where sp.ProvinceCode == provinceCode && sp.CityCode == cityCode
                        select new AreaCodeName { Code = sp.AreaCode, Name = sp.AreaName };
            var areas = query.Distinct().ToList();
            return areas;
        }
        public virtual IList<Area> GetAreasByCityName(string cityname, bool showHidden = false)
        {
            string key = string.Format(AREAS_ALL_KEY, cityname);
            return _cacheManager.Get(key, () =>
            {
                var query = from sp in _areaRepository.Table
                            orderby sp.DisplayOrder
                            where sp.CityCode == cityname &&
                            (showHidden || sp.Published)
                            select sp;
                var areas = query.ToList();
                return areas;
            });
        }
        public virtual void InsertArea(Area Area)
        {
            if (Area == null)
                throw new ArgumentNullException("Area");

            _areaRepository.Insert(Area);

            _cacheManager.RemoveByPattern(AREAS_PATTERN_KEY);

        }

        public virtual void UpdateArea(Area Area)
        {
            if (Area == null)
                throw new ArgumentNullException("Area");

            _areaRepository.Update(Area);

            _cacheManager.RemoveByPattern(AREAS_PATTERN_KEY);

        }

        #endregion
    }
}
